package com.hdy.common.log;


import static com.hdy.common.log.LTagPriority.TAG_CLASS;

public class LTagPrinter {
    private static final int MIN_STACK_OFFSET = 3;

    private static final String DEFAULT_TAG = "HDY";

    private LTagPriority mLTagPriority = TAG_CLASS;

    private int sStackIndex = -1;

    public LTagPrinter() {
    }

    public void setLTagPriority(LTagPriority tagPriority) {
        mLTagPriority = tagPriority;
    }

    /**
     * 确保调用路径
     *
     * @return
     */
    public String generateTag() {
        String tagStr = null;
        switch (mLTagPriority) {
            case TAG_UNIFIED:
                return DEFAULT_TAG;
            case TAG_CLASS:
                return getClassTag();
            case TAG_CLASS_LINE:
                return getClassAndLineTag();
            default:
                break;
        }
        return tagStr;
    }

    public String generateTag(String tag) {
        return DEFAULT_TAG + " " + tag;
    }

    private String getClassAndLineTag() {
        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
        int stackOffset = getStackOffset(trace);
        if (stackOffset == -1 || stackOffset >= trace.length) {
            return DEFAULT_TAG;
        }
        return getTagTop() + " " + getClassAndlineByStack(trace[stackOffset]);
    }

    private String getClassTag() {
        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
        int stackOffset = getStackOffset(trace);
        if (stackOffset == -1 || stackOffset >= trace.length) {
            return DEFAULT_TAG;
        }
        return getTagTop() + " " + getClassByStack(trace[stackOffset]);
    }

    private String getClassAndlineByStack(StackTraceElement caller) {
        if (caller == null) {
            return "";
        }
        String stackTrace = caller.toString();
        stackTrace = stackTrace.substring(stackTrace.lastIndexOf('('), stackTrace.length());
        String tag = "%s.%s%s";
        String callerClazzName = caller.getClassName();
        callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
        tag = String.format(tag, callerClazzName, caller.getMethodName(), stackTrace);
        return tag;
    }

    private String getClassByStack(StackTraceElement caller) {
        if (caller == null) {
            return "";
        }
        String callerClazzName = caller.getClassName();
        callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1);
        return callerClazzName;
    }

    private int getStackOffset(StackTraceElement[] trace) {
        if (sStackIndex != -1) {
            return sStackIndex;
        }
        try {
            String logPkg = this.getClass().getPackage().getName();
            for (int i = MIN_STACK_OFFSET; i < trace.length; i++) {
                if (isStackTraceElementInPackage(logPkg, trace[i]) &&
                        i < trace.length - 1 &&
                        isStackTraceElementInPackage(logPkg, trace[i + 1])) {
                    continue;
                }
                if (isStackTraceElementInPackage(logPkg, trace[i])) {
                    sStackIndex = i + 1;
                    return sStackIndex;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sStackIndex;
    }

    private boolean isStackTraceElementInPackage(String pkg, StackTraceElement stackTraceElement) {
        String epkg = stackTraceElement.getClassName().substring(0, stackTraceElement.getClassName().lastIndexOf("."));
        return epkg.equals(pkg);
    }

    private String getTagTop() {
        return DEFAULT_TAG;
    }
}
